package fem2d;

import java.util.ArrayList;

import fem2.AbstractStructuralStaticDemo;
import fem2.Constraint;
import fem2.Element;
import fem2.GravityLoad;
import fem2.Load;
import fem2.MaterialModel;
import fem2.Mesh;
import fem2.MeshGenerator;
import fem2.MeshPart;
import fem2.MeshUtilities;
import fem2.Model;
import fem2.Node;
import fem2.StringUtilities;
import fem2.element.StructuralElement;
import fem2.enu.State;
import fem2.material.DruckerPragerMM;
import fem2.material.FluencyCriteria;
import fem2.material.LinearIsotropicHardeningRule;
import fem2.observer.GidPlasticityObserver;
import fem2.observer.TimeStepObserver;
import fem2.pre_and_post.GidMeshGenerator;
import fem2.strategies.Strategy;

/**
 * test model for b-bar method & drucker-prager model
 * 
 * @author hbui
 * 
 */
public class Square extends AbstractStructuralStaticDemo {

	public Square() {
		projectDir = "/home/hbui/kratos_janosch";
		projectName = "square.gid";
	}

	// @Override
	// public Mesh createMesh() {
	// meshFileName = "mesh2.msh"; //quadrilateral patch mesh
	// MeshGenerator mg = new PatchMeshGenerator(6, 6, 0.0, 0.0, 0.2, 0.2);
	// return mg.getMesh(2);
	// }

	@Override
	public Mesh createMesh() {
		meshFileName = "mesh1.msh"; // 8-node quadrilateral mesh
		// meshFileName = "mesh3.msh"; // 4-node quadrilateral mesh
		// meshFileName = "mesh4.msh"; // quadratic triangle mesh
		String fn = projectDir + '/' + projectName + '/' + meshFileName;
		MeshGenerator mg = new GidMeshGenerator(fn);
		Mesh mesh = mg.getMesh(2);
		return mesh;
	}

	@Override
	public Model createConditions(Model m) {
		Mesh mesh = m.getMesh();
		Constraint cx = new Constraint(false, true);
		Constraint cy = new Constraint(true, false);

		ArrayList<Node> bottom = MeshUtilities.seekNodesOnSurface(mesh, 0.0, 1.0, 0.0);
		ArrayList<Node> left = MeshUtilities.seekNodesOnSurface(mesh, 1.0, 0.0, 0.0);
		ArrayList<Node> right = MeshUtilities.seekNodesOnSurface(mesh, 1.0, 0.0, -1.0);

		mesh.addConstraint(cy, bottom);
		mesh.addConstraint(cx, left);
		mesh.addConstraint(cx, right);

		double density = 2e3;
		for (int i = 0; i < mesh.countFaces(); i++) {
			Load l = new GravityLoad(mesh.getFace(i), density);
			m.addLoad(l);
		}

		// ArrayList<Node> top = MeshUtilities.seekNodesOnSurface(mesh, 0.0,
		// 1.0, -1.0);
		// Constraint pc = new Constraint(true, false);
		// pc.setValue(1, -0.1);
		// mesh.addConstraint(pc, top);

		return m;
	}

	@Override
	public MaterialModel createMaterial(Model m) {
		double E = 20e6;
		double nu = 0.49;
		double thickness = 1.0;
		State ss = State.PLANE_STRAIN;
		double rho = 0.0;

		/*
		 * approximation of inner edge of Mohr-Coulomb yield surface
		 */
		double phi = (20.0 / 180) * Math.PI;
		double eta = 6 * Math.sin(phi) / Math.sqrt(3) / (3 + Math.sin(phi));
		double xi = 6 * Math.cos(phi) / Math.sqrt(3) / (3 + Math.sin(phi));
		double etabar = eta;// associative flow

		double c = 50e3;
		double H = 0;
		FluencyCriteria isoLaw = new LinearIsotropicHardeningRule(c, H);

		return new DruckerPragerMM(E, nu, thickness, rho, ss, eta, etabar, xi, isoLaw);

	}

	@Override
	public Element createElement(MeshPart mp, MaterialModel mm) {
		StructuralElement e = new StructuralElement(mp, mm);
		// e.setIntegrationType(IntegrationType.SELECTIVE_REDUCED_INTEGRATION);

		// Element e = new BBarStructuralElement(mp, mm);

		// e.setEchoLevel(EchoLevelType.DEBUG);

		return e;
	}

	@Override
	public void addObservers(Model m, Strategy s, TimeStepObserver o) {
		super.addObservers(m, s, o);

		String meshName = StringUtilities.getFileName(meshFileName);

		s.addObserver(new GidPlasticityObserver(m, o, projectDir, projectName, meshName));
	}

	public static void main(String[] args) {
		AbstractStructuralStaticDemo demo = new Square();

		demo.run();
	}
}
